using Runtime.Common.Editor;
using UnityEditor;
using UnityEngine;

namespace Runtime.Module.GameGraphic.Editor
{
    public class GameScriptSet<T> where T : Component
    {
        public GameScriptSet()
        {
        }

        public GameScriptSet(SerializedObject serializedObject, T target, string nodeInfoCtrlName)
        {
            this.serializedObject = serializedObject;
            this.target = target;
            NodeInfoCtrlName = nodeInfoCtrlName;
        }

        public bool IsScript { get; set; }
        private SerializedProperty nodeInfoList;
        public SerializedObject serializedObject { get; set; }
        private SerializedObject gameobjectControlserializedObject;
        private EntityNode _control;
        public T target { get; set; }
        private int index = -1;
        private SerializedProperty _NodeInfoCtrl;
        public string NodeInfoCtrlName;
        public bool IsGUI = false;

        public void GetScriptStute()
        {
            _control = GetControl();
            if (!_control)
            {
                IsGUI = false;
                //Debug.LogError($"xxxxxxxxxxxxx=========xxxxxxxx{target.name}");
                return;
            }

            // Debug.LogError($"xxxxxxxxxxxxxxxxxxxxx{_control.name}");
            IsGUI = true;
            gameobjectControlserializedObject = new SerializedObject(_control);
            _NodeInfoCtrl = gameobjectControlserializedObject.FindProperty(NodeInfoCtrlName);
            nodeInfoList = _NodeInfoCtrl.FindPropertyRelative("list");
            nodeInfoList.ArrayForEach(GetScript);
        }

        public virtual EntityNode GetControl()
        {
            Transform parent = target.transform.parent;
            return parent
                ? parent.GetComponentInParent<EntityNode>()
                : target.GetComponentInParent<EntityNode>();
        }

        private bool GetScript(SerializedProperty property, int index)
        {
            SerializedProperty Node = property.FindPropertyRelative("Node");
            if (Node == null)
            {
                return false;
            }

            T obj = Node.objectReferenceValue as T;
            if (obj == null)
            {
                return false;
            }

            if (obj == target)
            {
                IsScript = true;
                this.index = index;
                return true;
            }

            return false;
        }

        public void SetScriptStute()
        {
            //Debug.LogError($"是否已修改 {gameobjectControlserializedObject.hasModifiedProperties}");
            /*所关联的实际对象（比如游戏对象、组件等）的当前状态更新到序列化对象中.
             更新上次修改数据到当前，然后继续操作
            实际对象的属性等可能会通过多种途径被改变，
            例如用户在 Inspector（检视窗口）中手动修改了组件的属性，
            或者其他脚本在运行时对相关对象做了操作等，
            而序列化对象中缓存的序列化数据不会自动随之更新，
            所以需要调用 Update 方法来手动刷新状态。*/
            gameobjectControlserializedObject.Update();
            //gameobjectControlserializedObject.UpdateIfRequiredOrScript();
            if (!IsScript)
            {
                if (index >= 0)
                {
                    nodeInfoList.ReMoveAtIndex(index);
                    index = -1;
                }
            }
            else
            {
                // Debug.LogError(
                //     $"{gameobjectControlserializedObject.targetObject.GetInstanceID()}--->Add ---> {NodeInfoCtrlName} ---->{IsScript} ");
                if (index < 0)
                {
                    SerializedProperty property = nodeInfoList.AddList();
                    SerializedProperty node = property.FindPropertyRelative("Node");
                    node.objectReferenceValue = target;
                    SerializedProperty path = property.FindPropertyRelative("Path");
                    string pathTemp = $"";
                    GetPath(target.transform, ref pathTemp);
                    if (target is MonoBehaviour)
                    {
                        pathTemp = $"{pathTemp}@{target.GetType().Name}";
                    }

                    path.stringValue = pathTemp;

                    index = nodeInfoList.arraySize - 1;
                }
            }

            gameobjectControlserializedObject.SetIsDifferentCacheDirty();
            gameobjectControlserializedObject.ApplyModifiedProperties();
        }

        private void GetPath(Transform parent, ref string path, bool isStart = true)
        {
            path = isStart ? parent.name : $"{parent.name}/{path}";
            parent = parent.parent;
            if (parent && !parent.GetComponent<EntityNode>())
            {
                GetPath(parent, ref path, false);
            }

            path = path.TrimEnd('/');
        }
    }
}